#pragma once

#include "ListItem.h"
#include "Timer.h"

#include <vector>

class CListStyle
{
public:
  COLORREF clrBackground1;
  COLORREF clrBackground2;
  HBRUSH   hbrBackground;

  CListStyle() : clrBackground1(0), clrBackground2(0), hbrBackground(NULL)
  {}
};

class CList
{
protected:
  typedef std::vector<CListItem*> CListItems;

public:
  CList(HWND hParent = NULL, int itemHeight = 0);
  virtual ~CList();

  virtual void Clear();

  virtual bool OnKeyDown(int vKey, bool bRepeating);
  virtual bool OnKeyUp(int vKey);

  virtual bool OnMouseDown(int x, int y);
  virtual bool OnMouseMove(int x, int y);
  virtual bool OnMouseUp(int x, int y);

  void DoBounce();  // avian

  void SetParent(HWND hParent)
  { parentWnd = hParent; }

  virtual const RECT& GetRect() const
  { return rect; }
  virtual void SetRect(const RECT& rc);

  int GetHeight() const
  { return height; }

  void SetStyle(const CListStyle& listStyle)
  { style = listStyle; }
  const CListStyle& GetStyle() const
  { return style; }

  void SetScroll(int nScrolled)
  { scrolled = nScrolled; }
  int  GetScroll() const
  { return scrolled; }

  bool IsDragging() const
  { return isDragging; }
  bool IsScrolling() const
  { return isScrolling; }
  bool IsBouncing() const
  { return scrollOffset != 0; }
  bool IsMoving() const
  { return isDragging || isScrolling || scrollOffset != 0; }

  virtual void CalculateHeights();

  virtual void Redraw()
  { ::InvalidateRect(parentWnd, &rect, FALSE); }

  virtual void Draw(HDC hdc, HDC hdcTmp, const RECT& rClip);

  int GetCount() const
  { return (int)this->items.size(); }

  CListItem* GetAt(int index)
  { return this->items[index]; }
  const CListItem* GetAt(int index) const
  { return this->items[index]; }

  CListItem* GetSel()
  {
    if (this->selection >= 0 && this->selection < (int)items.size())
      return this->items[this->selection];
    else
      return NULL;
  }
  const CListItem* GetSel() const
  { return GetSel(); }
  int GetSelection(void) const
  { return this->selection; }
  void SetSelection(int index = -1, bool redraw = false);
  int GetHover(void) const
  { return this->hover; }
  void SetHover(int index = -1, bool redraw = true);

public:
  void OnLongTapTimer(UINT nID, DWORD dwTime);
  void OnLongTapIndTimer(UINT nID, DWORD dwTime);
  void OnBounceTimer(UINT nID, DWORD dwTime);
  void OnScrollTimer(UINT nID, DWORD dwTime);
  void OnScrollToTimer(UINT nID, DWORD dwTime);

  bool IsItemVisible(int index) const;

  void SelectPrev();
  void SelectNext();
  void ScrollToSelection();
  void ScrollToSelectionFast();

  virtual void ScrollTo(int pos, int time);
  virtual void StopScrolling();

protected:
  void Add(CListItem* pItem);

  int  GetItemIdx(int y) const;
  RECT GetItemIndicatorRect(int idx, bool screen = true) const; // added for avian
  RECT GetItemRect(int idx, bool screen = true) const;

  void UpdateScrollMax()
  { scrollMax = height - (rect.bottom - rect.top); 
    if (scrollMax < 0) scrollMax = 0; }

  void MoveList(double delta);

  void StartLongTap();
  void DrawLongTapInd(HDC hdc, int item, int progress);

protected:
  HWND parentWnd;
  
  int  startY;
  int  lastY;
  int deltaYAccum; // Avian

  bool isMinimizing;

  bool abortKineticScroll; // Avian
  bool isScrolling;
  bool isDragging;
  int  scrolled;
  int  scrollMax;
  double scrollSpeed;
  double scrollLastSpeed;
  double scrollOffset;
  double scrollStart;
  double scrollChange;
  double scrollDuration;
  DWORD  scrollStartTime;
  DWORD  tStartTime;
  DWORD  tLastMovement; // Avian
  TimerInst<CList, &CList::OnScrollTimer>   scrollTimer;
  TimerInst<CList, &CList::OnScrollToTimer> scrollToTimer;
  TimerInst<CList, &CList::OnBounceTimer>   bounceTimer;

  RECT rect;
  int  height;
  int  defaultItemHeight;

  std::vector<int> itemPos;
  int              avgItemHeight;

  CListItems items;
  CListStyle style;

  int  selection;
  int  hover;

  TimerInst<CList, &CList::OnLongTapTimer>    longTapTimer;
  TimerInst<CList, &CList::OnLongTapIndTimer> longTapIndTimer;
  DWORD tLongTapStartTime;
  bool skipMouseAction;
  bool skipKeyboardAction;

  // avian
  bool  bHideLetterOverlay;
  int   nKeyRepeatCount;
  int   posOffset;
};